package org.web.common.sso.server.controller;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.web.base.domain.ResultDO;
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.helper.ResultHelper;
import org.web.base.domain.helper.ServiceExceptionHelper;
import org.web.base.helper.HttpRequestHelper;
import org.web.base.helper.filter.URIHelper;
import org.web.common.sso.client.biz.impl.PropertiesConstantInterface;
import org.web.common.sso.server.biz.AbstractTokenBiz;
import org.web.common.sso.server.config.SSOServerConfig;
import org.web.common.sso.server.domain.AccountInfoDO;
import org.web.common.sso.server.domain.SsoTokenDO;
import org.web.common.sso.server.helper.SSOServerConstant;
import org.web.common.sso.server.helper.ServerControllerMessageEnum;
import org.web.common.sso.server.helper.redis.CacheSessionDO;
import org.web.common.sso.server.query.QueryAccountInfo;
import org.web.common.sso.server.query.QuerySsoToken;
import org.web.common.sso.server.service.AccountInfoService;
import org.web.common.sso.server.service.SsoTokenService;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.UUID;

@Controller
@RequestMapping("sessionAccount")
public class SessionAccountController implements PropertiesConstantInterface {

    Logger logger = LoggerFactory.getLogger(SessionAccountController.class);

    @Resource
    private AbstractTokenBiz tokenBiz;

    @Resource
    private AccountInfoService accountInfoService;

    @Resource
    private SsoTokenService ssoTokenService;

    @Resource
    private SSOServerConfig ssoServerConfig;

    @RequestMapping(value = "signIn", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public ResultDO<SsoTokenDO> signIn(String accountName, String password, String uri) {
        ResultDO<SsoTokenDO> resultDO = new ResultDO<>();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        try {
            QueryAccountInfo queryAccountInfo = new QueryAccountInfo();
            queryAccountInfo.setAccountName(accountName);
            AccountInfoDO accountInfoDO = accountInfoService.selectOneAccountInfo(queryAccountInfo);
            if (ObjectUtils.isEmpty(accountInfoDO)) {
                accountInfoDO = new AccountInfoDO();
                accountInfoDO.setAccountName(accountName);
                if (StringUtils.isEmpty(password)) {
                    accountInfoDO.setAccountName(accountName);
                } else {
                    accountInfoDO.setAccountPassword(password);
                }
                accountInfoService.insertAccountInfo(accountInfoDO);

            } else if (!StringUtils.equals(password, accountInfoDO.getAccountPassword())) {
                resultDO = ResultHelper.buildResultDOByException(ServiceExceptionHelper.buildServiceException(ResultMessageEnum.SYSTEM_EXCEPTION, ServerControllerMessageEnum.ACCOUNT_AND_PASSWORD_ERROR.getMessage()));
            }
            if (resultDO.isSuccess()) {
                SsoTokenDO ssoTokenDO = writeCookie(servletRequestAttributes, accountInfoDO);
                resultDO.getExtendsDomain().put("forwardURL",  URIHelper.addParamToURL(uri,PARAMETER_SSO_EXCHANGE_TOKEN,ssoTokenDO.getSsoExchangeToken()));
                resultDO.setDomain(ssoTokenDO);
            }
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            resultDO = ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    private SsoTokenDO writeCookie(ServletRequestAttributes servletRequestAttributes, AccountInfoDO accountInfoDO) throws IOException {
        String cookieToken = UUID.randomUUID().toString();
        String exchangeToken = UUID.randomUUID().toString();
        //TODO
        SsoTokenDO ssoTokenDO = new SsoTokenDO();
        ssoTokenDO.setSsoToken(cookieToken);
        ssoTokenDO.setSsoExchangeToken(exchangeToken);
        ssoTokenDO.setAccountName(accountInfoDO.getAccountName());
        ssoTokenDO.setAccountNum(accountInfoDO.getAccountInfoId().toString());
        ssoTokenDO.setAccountInfoId(accountInfoDO.getAccountInfoId().toString());
        long expireTime = System.currentTimeMillis() + ssoServerConfig.getInCashTime() * SSOServerConstant.ONE_MINUTE_THOUSANDTH;
        ssoTokenDO.setExpireTime(expireTime);
        ssoTokenService.insertSsoToken(ssoTokenDO);
        Cookie cookie = new Cookie(PROPERTIES_TOKEN_NAME_DEFAULT_VALUE, accountInfoDO.getAccountName());
        cookie.setDomain(servletRequestAttributes.getRequest().getServerName());
        cookie.setPath("/");
        cookie.setValue(cookieToken);
        servletRequestAttributes.getResponse().addCookie(cookie);
        return ssoTokenDO;
    }

    @RequestMapping(value = "loginPage", method = {RequestMethod.POST, RequestMethod.GET})
    public String signInPage(String forwardUrl,boolean onlyLogin, Model model) throws IOException, URISyntaxException {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        model.addAttribute("forward_url", forwardUrl);
        if (!onlyLogin) {
            String ssoToken = HttpRequestHelper.getValueByParamOrCookie(servletRequestAttributes.getRequest(), PROPERTIES_TOKEN_NAME_DEFAULT_VALUE);
            if (StringUtils.isNoneBlank(ssoToken)) {
                ResultDO<CacheSessionDO> resultDO = tokenBiz.getAndRefreshCacheSessionDO(ssoToken);
                if (resultDO.isSuccess()) {
                    QuerySsoToken querySsoToken = new QuerySsoToken();
                    querySsoToken.setSsoToken(ssoToken);
                    SsoTokenDO ssoTokenDO = ssoTokenService.selectOneSsoToken(querySsoToken);
                    servletRequestAttributes.getResponse().sendRedirect(URIHelper.addParamToURL(forwardUrl,PARAMETER_SSO_EXCHANGE_TOKEN,ssoTokenDO.getSsoExchangeToken()));
                }
            }
        }
        return "loginPage";
    }

    @RequestMapping(value = "defaultWelcomePage", method = {RequestMethod.POST, RequestMethod.GET})
    public String defaultWelcomePage(Model model) {
        return "defaultWelcomePage";
    }

    @RequestMapping(value = "signOut", method = {RequestMethod.POST, RequestMethod.GET})
    public String signOut(String routingPage) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        Cookie cookie = HttpRequestHelper.getCookieByCookie(request, PROPERTIES_TOKEN_NAME_DEFAULT_VALUE);
        cookie.setMaxAge(0);
        HttpServletResponse response = servletRequestAttributes.getResponse();
        response.addCookie(cookie);
        return "loginPage";
    }
}
